﻿#region Legal

// Jimmy Zimmerman
// Team Mongoose
//
// END USER LICENSE AGREEMENT
// IMPORTANT - READ THIS CAREFULLY:  This End User License Agreement is a legal agreement
// between you (either an individual, business entity, currently active identity of an
// individual with Multiple Personality Disorder, octopus overlord, or otherworldly entity),
// and Team Mongoose, for the enclosed, components.
//
// By reading this document and/or installing this product, you agree to be bound by the
// terms of this EULA.
//
// Team Mongoose owns all copyright, trade secret, trademark, trade wars,
// patent, portent, and potential rights to these components.  Team Mongoose
// grants you the right to deploy the enclosed components.
//
// If you agree to the terms of this EULA, a license to use these components is granted to you.
//
// If you should happen to benefit from the enclosed components, then you are legally and
// contractually bound to thank us for it. Send your regards to jimmyzimms@hotmail.com.
//
// OTHER RIGHTS AND LIMITATONS
// You may not reverse-engineer, decompile, decode, disassemble, psycho-analyze, or otherwise
// attempt to find hidden meanings between the lines of this EULA; unless, of course, you should
// happen to find some, and they are funny.
//
// You may not translate this EULA or any part of the components into Ancient Sumerian.
//
// THESE COMPONENTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. ANY USE OF THE COMPONENTS
// CONTAINED IS AT YOUR OWN RISK. TEAM MONGOOSE DISCLAIM ALL WARRANTIES, EITHER
// EXPRESS OR IMPLIED, WITH RESPECT TO THE ACCURRACY AND CORRECTNESS OF THE COMPONENTS CONTAINED
// HEREIN. TEAM MONGOOSE DOES NOT WARRANT THAT THE COMPONENTS ARE FLAWLESS.
//
// REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS, WITH OR WITHOUT MODIFICATION, ARE PERMITTED
// PROVIDED THAT THE FOLLOWING CONDITIONS ARE MET:
// * REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THE ABOVE COPYRIGHT NOTICE
// * REDISTRIBUTIONS IN BINARY FORM MUST NOTE THE USE OF THE COMPONENT IN DOCUMENTATION AND/OR
//   OTHER MATERIALS PROVIDED WITH THE DISTRIBUTION.
// * NEITHER THE NAME OF TEAM MONGOOSE MAY BE USED TO ENDORES OR PROMOTE PRODUCTS
//   DERIVED FROM THIS SOFTWARE WITHOUT SPECIFIC PRIOR WRITTEN PERMISSION.
//
// IN NO EVENT SHALL TEAM MONGOOSE BE HELD LIABLE FOR INCIDENTAL, SPECIAL, INDIRECT,
// INCONSEQUENTIAL, UNBELIEVABLE, EXAGGERATED, VERBOSE, OR TYPICAL DAMAGES INCURRED WHILE USING
// THE ENCLOSED COMPONENTS.
//
// OUR STUFF ALWAYS WORKS - SOMETIMES.

#endregion

using System;
using System.Collections.Generic;
using System.Windows.Media;

namespace Mongoose.Games.BfgRoster
{
    /// <summary>
    /// Represents the definition of a BFG ship class definition.
    /// </summary>
    /// <remarks>In general this type is used for all BFG ship class definitions regardless of race, size, or ability.</remarks>
    public class ShipClass : IMutableLockingItem
    {
        #region Fields

        private static readonly IDictionary<VesselType, Int32> Capacities = new ReadOnlyDictionary<VesselType, Int32>(new Dictionary<VesselType, Int32>
                                                          {
                                                              {VesselType.BattleCruiser, 8},
                                                              {VesselType.Battleship, 10},
                                                              {VesselType.Cruiser, 8},
                                                              {VesselType.Escort, 1},
                                                              {VesselType.GrandCruiser, 10},
                                                              {VesselType.LightCruiser, 6},
                                                              {VesselType.Orbital, 1}
                                                          });

        private readonly LockableList<Loadout<Armament>> armaments;
        private readonly LockableList<Loadout<Ordinance>> ordinance;
        private readonly VesselType vesselType;
        private String name;
        private Int32 damageCapacity;
        private Int32 speed;
        private Int32 turnDegrees;
        private Int32 shields;
        private ArmorRating armor;
        private Int32 turrets;
        private readonly ImageSource image;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ShipClass"/> class.
        /// </summary>
        /// <param name="vesselType">The type of the vessel.</param>
        /// <param name="name">The name of the ship class.</param>
        /// <param name="image">An <see cref="ImageSource"/> containing a graphical representation of the <see cref="ShipClass"/>.</param>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="name"/> is null, empty, or whitespace</para>
        /// <para>-OR-</para>
        /// <para><paramref name="image"/> is null</para>
        /// </exception>
        public ShipClass(String name, VesselType vesselType, ImageSource image)
        {
            name = (name ?? String.Empty).Trim();
            if (name.IsNullOrWhiteSpace()) throw new ArgumentNullException("name", "The value cannot be null, empty, or only contain whitespace characters.");
            if (image == null) throw new ArgumentNullException("image");

            this.name = name;
            this.armaments = new LockableList<Loadout<Armament>>();
            this.ordinance = new LockableList<Loadout<Ordinance>>();
            this.vesselType = vesselType;
            this.armor = new ArmorRating(5);
            this.damageCapacity = StandardCapacities[vesselType];
            this.image = image;
        }

        #endregion
        
        #region Properties

        /// <summary>
        /// Gets the standard damage capacity for each <see cref="VesselType"/>.
        /// </summary>
        /// <value>The standard damage capacity for each <see cref="VesselType"/>.</value>
        public static IDictionary<VesselType, Int32> StandardCapacities
        {
            get { return Capacities; }
        }

        /// <summary>
        /// Gets or sets the name of the ship class.
        /// </summary>
        /// <value>The name of the ship class.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentNullException">The supplied value is null, empty, or whitespace.</exception>
        public virtual String Name
        {
            get { return this.name; }
            set
            {
                value = (value ?? String.Empty).Trim();
                if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException("Name", "The value cannot be null, empty, or only contain whitespace characters.");

                this.CheckLock();

                this.name = value;
            }
        }

        /// <summary>
        /// Gets the <see cref="VesselType"/> that the ship classification is.
        /// </summary>
        /// <remarks>While most values can be changed at game start, you simply cannot change a battleship into an escort. It doesn't make sense :)</remarks>
        /// <value>The <see cref="VesselType"/> that the ship classification is.</value>
        public virtual VesselType VesselType
        {
            get { return this.vesselType; }
        }

        /// <summary>
        /// Gets or sets the total number of hits a vessel can take before destruction.
        /// </summary>
        /// <value>The total number of hits a vessel can take before destruction.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The supplied value is less than 1.</exception>
        public virtual Int32 DamageCapacity
        {
            get { return this.damageCapacity; }
            set
            {
                this.CheckLock();
                this.damageCapacity = value;
            }
        }

        /// <summary>
        /// Gets or sets the base speed of the ship class.
        /// </summary>
        /// <value>The base speed of the ship class.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The supplied value is less than 0.</exception>
        public virtual Int32 Speed
        {
            get { return this.speed; }
            set
            {
                this.CheckLock();
                this.speed = value;
            }
        }

        /// <summary>
        /// Gets or sets the number of degrees the vessel can make in a single turn movement.
        /// </summary>
        /// <value>The number of degrees the vessel can make in a single turn movement.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The supplied value is less than 1.</exception>
        public virtual Int32 TurnDegrees
        {
            get { return this.turnDegrees; }
            set
            {
                this.CheckLock();
                this.turnDegrees = value;
            }
        }

        /// <summary>
        /// Gets or sets the number of shield hits the vessel can absorb.
        /// </summary>
        /// <value>The number of shield hits the vessel can absorb.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The supplied value is less than 0.</exception>
        public virtual Int32 Shields
        {
            get { return this.shields; }
            set
            {
                this.CheckLock();
                this.shields = value;
            }
        }

        /// <summary>
        /// Gets the <see cref="ArmorRating"/> for the current vessel.
        /// </summary>
        /// <value>The <see cref="ArmorRating"/> for the current vessel.</value>
        public virtual ArmorRating Armor
        {
            get { return this.armor; }
            set
            {
                this.CheckLock();
                this.armor = value;
            }
        }

        /// <summary>
        /// Gets or sets the number of defensive turrets the vessel has.
        /// </summary>
        /// <value>The number of defensive turrets the vessel has.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The supplied value is less than 0.</exception>
        public virtual Int32 Turrets
        {
            get { return this.turrets; }
            set
            {
                this.CheckLock();
                this.turrets = value;
            }
        }

        /// <summary>
        /// Gets the <see cref="ImageSource"/> representation of the ship class.
        /// </summary>
        /// <value>The <see cref="ImageSource"/> representation of the ship class.</value>
        public virtual ImageSource Image
        {
            get { return this.image; }
        }

        /// <summary>
        /// Gets or sets the number of <see cref="Armament"/>
        /// </summary>
        /// <value>The number of defensive turrets the vessel has.</value>
        /// <exception cref="InvalidOperationException">The current instance is locked for modification.</exception>
        public virtual IList<Loadout<Armament>> Armaments
        {
            get { return this.armaments; }
        }

        public virtual IList<Loadout<Ordinance>> Ordinance
        {
            get { return ordinance; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Used to confirm that the current <see cref="ShipClass"/> instance is not <see cref="IsLocked">locked</see> for modification.
        /// </summary>
        /// <remarks>Properties that can only be modified until the instance is <see cref="Lock">locked</see> should call this method before changing the stored value.</remarks>
        /// <see cref="InvalidOperationException">The current <see cref="ShipClass"/> instance is locked for modification.</see>
        protected virtual void CheckLock()
        {
            if (this.IsLocked) throw new InvalidOperationException("The current ship class instance is locked for modification of the ship characteristics.");
        }

        #endregion

        #region IMutableLockingItem Members

        /// <summary>
        /// Indicates if the current instance is locked for modification.
        /// </summary>
        /// <value>True if the current instance is locked for further modification; otherwise false.</value>
        public virtual Boolean IsLocked { get; protected set; }

        /// <summary>
        /// Locks the current instance settings against further modification.
        /// </summary>
        /// <remarks>
        /// Multiple calls to this method will not raise an exception. Once locked, this instance will remain immutable
        /// for the remainder of the game.
        /// </remarks>
        public virtual void Lock()
        {
            this.IsLocked = true;
            this.armaments.Lock();
            this.ordinance.Lock();
        }

        #endregion
    }
}
